﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace SurvivalStrategy.Modules
{
    public enum ActionTags
    {
        Null,
        Moving,
        Attacking,
        Communication,
        Defending,
        Interaction
    }

    //klasa abstrakcyjna po ktorej dziedzicza wszystkie action module
    public abstract class ActionModule
    {
        private List<ActionModuleFunction> moduleFunctions;
        public List<ActionModuleFunction> ModuleFunctions { get { return moduleFunctions; } }
        private static SurvivalStrategy.EntitiesManager entitiesManager; 
        private static World world;
        private static bool setValues = false;
        private int id = -1;


        public ActionModule()
        {
            moduleFunctions = new List<ActionModuleFunction>();
        }

        protected void AddFunction(ActionModuleFunc actionModuleFunction, ActionModulePriority actionModulePriority, ActionTags tag)
        {
            moduleFunctions.Add(new ActionModuleFunction(actionModuleFunction, actionModulePriority, tag));
        }

        protected void SetExclusiveFlag(bool val, ActionModuleFunc actionModuleFunction)
        {
            foreach (ActionModuleFunction func in moduleFunctions)
                if (func.ActionModuleFunc == actionModuleFunction)
                    func.SetExclusiveFlag = val;
        }

        public void SetID(int id)
        {
            if (this.id == -1)
                this.id = id;
        }

        public static void SetWorld(World w)
        {
            if (world == null)
                world = w;
        }

        public int GetID()
        {
            return id;
        }
     
        public static void SetValues(SurvivalStrategy.EntitiesManager eManager)
        {
            if (setValues)
                return;
            setValues = true;
            entitiesManager = eManager;
        }
        #region GetValuesFromID
        public Vector3 GetPosition(int id)
        {
            return entitiesManager.GetEntity(id).WorldInfo.Position;
        }

        public Vector3 GetForwardVector(int id)
        {
            return entitiesManager.GetEntity(id).WorldInfo.Forward;
        }

        public int GetAppearance(int id)
        {
            return entitiesManager.GetEntity(id).WorldInfo.Appearance;
        }

        public string GetName(int id)
        {
            return entitiesManager.GetEntity(id).WorldInfo.Name;
        }

        public Attributes GetAttributes(int id)
        {
            return entitiesManager.GetEntity(id).WorldInfo.PersonalAttributes;
        }
        #endregion
        #region GetValues
        public Vector3 GetPosition()
        {
            return entitiesManager.GetEntity(this.id).WorldInfo.Position;
        }

        public Vector3 GetForwardVector()
        {
            return entitiesManager.GetEntity(this.id).WorldInfo.Forward;
        }

        public int GetAppearance()
        {
            return entitiesManager.GetEntity(this.id).WorldInfo.Appearance;
        }

        public string GetName()
        {
            return entitiesManager.GetEntity(this.id).WorldInfo.Name;
        }

        public Attributes GetAttributes()
        {
            return entitiesManager.GetEntity(this.id).WorldInfo.PersonalAttributes;
        }
        #endregion
        #region SetValues
        public void SetSetName(string name)
        {
            entitiesManager.GetEntity(this.id).WorldInfo.Name = name;
        }

        public Entity GetEntitiy()
        {
            return entitiesManager.GetEntity(this.id);
        }

        public void SetPosition(Vector3 position)
        {
            entitiesManager.GetEntity(this.id).WorldInfo.Position = position;
        }

        public void SetForward(Vector3 forward)
        {
            entitiesManager.GetEntity(this.id).WorldInfo.Forward = forward;
        }

        public void SetAppearance(int appearance)
        {
            entitiesManager.GetEntity(this.id).WorldInfo.Appearance = appearance;
        }
        #endregion
        #region Memory
        protected Memory.MemorySegment GetMemoryValue(string key)        //pobiera wartosc z pamieci o podanej nazwie
        {
            if (entitiesManager.GetEntity(this.id).Memory.ContainsKey(key))
                return entitiesManager.GetEntity(this.id).Memory[key];
            else return null;
        }

        protected bool SetMemoryValueInNone(string key, Memory.MemorySegment segment)  //ustawia wartosc do pamieci pod podana nazwe, tylko jezeli jeszcze takiej nie uzyl
        {
            if (!entitiesManager.GetEntity(this.id).Memory.ContainsKey(key))
            {
                entitiesManager.GetEntity(this.id).Memory.Add(key, segment);
                return true;
            }
            else return false;
        }

        protected void SetForceMemoryValue(string key, Memory.MemorySegment segment)  //ustawia wartosc do pamieci pod podana nazwe, jezeli juz istnieje taki klucz, podmienia wartosc
        {
            if (!entitiesManager.GetEntity(this.id).Memory.ContainsKey(key))
            {
                entitiesManager.GetEntity(this.id).Memory.Add(key, segment);
            }
            else entitiesManager.GetEntity(this.id).Memory[key] = segment;
        }

        protected bool ForceSetMemoryValue(string key, Memory.MemorySegment segment)  //sprawdza czy podana klucz juz istnieje
        {
            return entitiesManager.GetEntity(this.id).Memory.ContainsKey(key);
        }

        protected void RemoveMemoryValue(string key)  //usuwa dany klucz
        {
            if (entitiesManager.GetEntity(this.id).Memory.ContainsKey(key))
                entitiesManager.GetEntity(this.id).Memory.Remove(key);
        }
        #endregion

        public T GetComponent<T>() where T : Entities.EnitityComponents.EntitiyComponent
        {
            return entitiesManager.GetEntity(this.id).GetComponent<T>();
        }

        public T GetComponent<T>(int id) where T : Entities.EnitityComponents.EntitiyComponent
        {
            return entitiesManager.GetEntity(id).GetComponent<T>();
        }

        protected List<WorldData.WorldElement> GetWorldElementAbsolutePosition(Vector3 position)   //bierze element z danego pola
        {
            return world.GetPositionsElements(position);
        }

        protected List<WorldData.WorldElement> GetWorldElementRelativePosition(Vector3 position)   //bierze element w odleglosci o jakas od naszej
        {
            return world.GetPositionsElements(Vector3.Add(GetPosition(), position));
        }

        protected void RemoveElementFromRelativePosition(Vector3 position, WorldData.WorldElement element)
        {
            world.GetPositionsElements(Vector3.Add(GetPosition(), position)).Remove(element);
        }

        protected void RemoveElement(WorldData.WorldElement element)
        {
            WorldData.WorldChunk chunk = element.ChunkOwner;
            List<List<WorldData.WorldElement>> owners = element.Owners;
            foreach(List<WorldData.WorldElement> o in owners)
                o.Remove(element);
            chunk.ChunkElements.Remove(element.ID);
        }

        protected void RemoveElementFromAbsolutePosition(Vector3 position, WorldData.WorldElement element)
        {
            world.GetPositionsElements(position).Remove(element);
        }

        protected WorldData.Colliders.Collider GetCollider()   //bierze element w odleglosci o jakas od naszej
        {
            return entitiesManager.GetEntity(id).GetComponent<Entities.EnitityComponents.EntitiyCollider>().Collider;
        }
    }
}
